[BZOJ2406]矩阵

2020-02-01
BZOJ

题意

给定$n*m$矩阵$\mathbb{A}$,求$\mathbb{B}$,$b_{i,j}\in[L,R]$,使得$max_{j=1}^{m}\{|\sum_{i=1}^{n}(a_{i,j}-b_{i,j})|\}$和$max_{i=1}^{n}\{|\sum_{j=1}^{m}(a_{i,j}-b_{i,j})|\}$中的max最小

输出这个最小值

题解

最大值最小化,按照套路是二分答案,现在变成可行性问题

给每一行每一列建一个节点,每一行的取值显然在$[suml_{i}-mid,suml_i+mid]$之间,分给m列的时候值又在$[L,R]​$之间,每一列也有与行类似的取值范围,容易想到建两层的网络图,转化为有源汇有上下界的可行流判定问题

超级源点和汇点流满就是可行

调试记录

1
if (flow == Max) return flow;

把这句话放到if外面大概慢了100倍,求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <cstdio>
#include <cstring>
#include <queue>
#include <cctype>
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int SS = 403;
const int TT = 404;
using namespace std;
struct E{
int to, nxt, f;
}e[maxn << 1]; int d[405], head[405], tot = 1;
void addedge(int u, int v, int f){
e[++tot].to = v, e[tot].nxt = head[u], e[tot].f = f;
head[u] = tot;
}
void ins(int u, int v, int l, int r){
d[u] -= l; d[v] += l;
addedge(u, v, r - l); addedge(v, u, 0);
}
int dep[405], now[405];
bool bfs(){
queue <int> q; while (!q.empty()) q.pop(); q.push(SS);
memset(dep, 0, sizeof dep); dep[SS] = 1; memcpy(now, head, sizeof now);
while (!q.empty()){
int cur = q.front(); q.pop();
for (int i = head[cur]; i; i = e[i].nxt){
int v = e[i].to;
if (e[i].f > 0 && dep[v] == 0){
dep[v] = dep[cur] + 1;
q.push(v);
}
}
}
return dep[TT] > 0;
}
int dfs(int cur, int Max){
if (cur == TT) return Max;
int flow = 0;
for (int i = now[cur]; i; i = e[i].nxt){
now[cur] = i;
int v = e[i].to;
if (e[i].f > 0 && dep[v] == dep[cur] + 1){
int tmp = dfs(v, min(Max - flow, e[i].f));
flow += tmp;
e[i].f -= tmp;
e[i ^ 1].f += tmp;
if (flow == Max) return flow;
}
}
return flow;
}
int maxflow;
void Dinic(){
maxflow = 0;
while (bfs()) maxflow += dfs(SS, INF);
}
int n, m, l[205], c[205], L, R;
bool check(int mid){
memset(head, 0, sizeof head); tot = 1;
memset(d, 0, sizeof d);
int S = 0, T = n + m + 1;
for (int i = 1; i <= n; i++){
ins(S, i, l[i] - mid, l[i] + mid);
for (int j = 1; j <= m; j++) ins(i, j + n, L, R);
} int sum = 0;
for (int i = 1; i <= m; i++) ins(i + n, T, c[i] - mid, c[i] + mid);
for (int i = 0; i <= n + m + 1; i++)
if (d[i] > 0) sum += d[i], addedge(SS, i, d[i]), addedge(i, SS, 0);
else if (d[i] < 0) addedge(i, TT, -d[i]), addedge(TT, i, 0);
addedge(T, S, INF);
Dinic();
return maxflow == sum;
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int a, j = 1; j <= m; j++){
scanf("%d", &a);
l[i] += a; c[j] += a;
}
scanf("%d%d", &L, &R);
int l = 0, r = 4e5, ans;
while (l <= r){
int mid = l + r >> 1;
if (check(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
} printf("%d\n", ans);
return 0;
}